// #[cfg(test)] does not seem to work here
#[allow(dead_code)]
pub mod grammars {
    use num_bigint::BigUint;

    use crate::grammarfile::parse_grammar;
    use num_traits::identities::{One, Zero};

    use crate::types::*;
    use num_rational::Ratio;

    lazy_static! {
        // use One::one, Zero::zero where possible
        static ref ONE_R: Ratio<BigUint> = Ratio::from_integer(BigUint::parse_bytes(b"1", 2).unwrap());
    }

    fn mk_rule_entries(input: &[(Prob, RHS)]) -> Vec<RuleEntry> {
        let mut cumul_lower: Prob = Zero::zero();
        let mut result = vec![];
        for (p, rhs) in input.iter() {
            result.push(RuleEntry {
                probability: p.clone(),
                cumul_lower: cumul_lower.clone(),
                rhs: rhs.clone(),
            });
            cumul_lower += p.clone();
        }
        result
    }

    pub fn easy2_prefixfree() -> SCFG {
        let grammarfile = r#"
---
  rules:
    0:
      - 0.96875 1 0
      - 0.03125 1 2
    1:
      - 0.125 "0"
      - 0.125 "1"
      - 0.125 "2"
      - 0.125 "3"
      - 0.125 "4"
      - 0.125 "5"
      - 0.125 "6"
      - 0.125 "7"
    2:
      - 1.0 ",""#;
        let parsed: Result<SCFG, anyhow::Error> = parse_grammar(grammarfile);
        parsed.unwrap()
    }

    pub fn linear_decimal() -> SCFG {
        SCFG {
            rules: [
                (
                    0,
                    vec![
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                from_float(0.8f64).unwrap(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(
                                from_float(0.0f64).unwrap(),
                            ),
                            rhs: vec![Symbol::Nonterminal(1), Symbol::Nonterminal(0)],
                        },
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                ONE_R.clone() - from_float(0.8f64).unwrap(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(
                                from_float(0.8f64).unwrap(),
                            ),
                            rhs: vec![Symbol::Nonterminal(1), Symbol::Terminals(b",".to_vec())],
                        },
                    ],
                ),
                (
                    1,
                    vec![
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(
                                from_float(0.0f64).unwrap(),
                            ),
                            rhs: vec![Symbol::Terminals(b"0".to_vec())],
                        },
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap(),
                            ),
                            rhs: vec![Symbol::Terminals(b"1".to_vec())],
                        },
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap() * BigUint::from(2_u32),
                            ),
                            rhs: vec![Symbol::Terminals(b"2".to_vec())],
                        },
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap() * BigUint::from(3_u32),
                            ),
                            rhs: vec![Symbol::Terminals(b"3".to_vec())],
                        },
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap() * BigUint::from(4_u32),
                            ),
                            rhs: vec![Symbol::Terminals(b"4".to_vec())],
                        },
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap() * BigUint::from(5_u32),
                            ),
                            rhs: vec![Symbol::Terminals(b"5".to_vec())],
                        },
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap() * BigUint::from(6_u32),
                            ),
                            rhs: vec![Symbol::Terminals(b"6".to_vec())],
                        },
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap() * BigUint::from(7_u32),
                            ),
                            rhs: vec![Symbol::Terminals(b"7".to_vec())],
                        },
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap() * BigUint::from(8_u32),
                            ),
                            rhs: vec![Symbol::Terminals(b"8".to_vec())],
                        },
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                ONE_R.clone()
                                    - from_float(0.1f64).unwrap() * BigUint::from(9_u32),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(
                                from_float(0.1f64).unwrap() * BigUint::from(9_u32),
                            ),
                            rhs: vec![Symbol::Terminals(b"9".to_vec())],
                        },
                    ],
                ),
            ]
            .iter()
            .cloned()
            .collect(),
        }
    }

    pub fn linear_with_powers_of_2() -> SCFG {
        SCFG {
            rules: [
                (
                    0,
                    vec![
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                from_float(0.5f64).unwrap(),
                            ),
                            cumul_lower: Zero::zero(),
                            rhs: vec![Symbol::Nonterminal(1), Symbol::Nonterminal(0)],
                        },
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                from_float(0.5f64).unwrap(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(
                                from_float(0.5f64).unwrap(),
                            ),
                            rhs: vec![Symbol::Nonterminal(1), Symbol::Terminals(b",".to_vec())],
                        },
                    ],
                ),
                (
                    1,
                    mk_rule_entries(&[
                        (
                            BinaryFraction::from_bigrational(from_float(0.125f64).unwrap()),
                            vec![Symbol::Terminals(b"0".to_vec())],
                        ),
                        (
                            BinaryFraction::from_bigrational(from_float(0.125f64).unwrap()),
                            vec![Symbol::Terminals(b"1".to_vec())],
                        ),
                        (
                            BinaryFraction::from_bigrational(from_float(0.125f64).unwrap()),
                            vec![Symbol::Terminals(b"2".to_vec())],
                        ),
                        (
                            BinaryFraction::from_bigrational(from_float(0.125f64).unwrap()),
                            vec![Symbol::Terminals(b"3".to_vec())],
                        ),
                        (
                            BinaryFraction::from_bigrational(from_float(0.125f64).unwrap()),
                            vec![Symbol::Terminals(b"4".to_vec())],
                        ),
                        (
                            BinaryFraction::from_bigrational(from_float(0.125f64).unwrap()),
                            vec![Symbol::Terminals(b"5".to_vec())],
                        ),
                        (
                            BinaryFraction::from_bigrational(from_float(0.125f64).unwrap()),
                            vec![Symbol::Terminals(b"6".to_vec())],
                        ),
                        (
                            BinaryFraction::from_bigrational(from_float(0.125f64).unwrap()),
                            vec![Symbol::Terminals(b"7".to_vec())],
                        ),
                    ]),
                ),
            ]
            .iter()
            .cloned()
            .collect(),
        }
    }

    /// A weighted Dyck_1 grammar
    pub fn dyck1(prob_zs: f32, prob_term: f32) -> SCFG {
        let prob_zs = from_float(prob_zs).unwrap();
        let prob_term = from_float(prob_term).unwrap();
        SCFG {
            rules: [
                (
                    0 as N,
                    mk_rule_entries(&[
                        (
                            BinaryFraction::from_bigrational(prob_zs.clone()),
                            vec![Symbol::Nonterminal(1), Symbol::Nonterminal(0)],
                        ),
                        (
                            BinaryFraction::from_bigrational(ONE_R.clone() - prob_zs),
                            vec![Symbol::Nonterminal(1)],
                        ),
                    ]),
                ),
                (
                    1 as N,
                    mk_rule_entries(&[
                        (
                            BinaryFraction::from_bigrational(prob_term.clone()),
                            vec![Symbol::Terminals(b"()".to_vec())],
                        ),
                        (
                            BinaryFraction::from_bigrational(ONE_R.clone() - prob_term),
                            vec![
                                Symbol::Terminals(b"(".to_vec()),
                                Symbol::Nonterminal(0),
                                Symbol::Terminals(b")".to_vec()),
                            ],
                        ),
                    ]),
                ),
            ]
            .iter()
            .cloned()
            .collect(),
        }
    }

    /// A weighted Dyck_1 grammar
    pub fn dyck1_strangely_numbered(prob_zs: f32, prob_term: f32) -> SCFG {
        let prob_zs = from_float(prob_zs).unwrap();
        let prob_term = from_float(prob_term).unwrap();
        SCFG {
            rules: [
                (
                    0 as N,
                    mk_rule_entries(&[
                        (
                            BinaryFraction::from_bigrational(prob_zs.clone()),
                            vec![Symbol::Nonterminal(2), Symbol::Nonterminal(0)],
                        ),
                        (
                            BinaryFraction::from_bigrational(ONE_R.clone() - prob_zs),
                            vec![Symbol::Nonterminal(2)],
                        ),
                    ]),
                ),
                (
                    2 as N,
                    mk_rule_entries(&[
                        (
                            BinaryFraction::from_bigrational(prob_term.clone()),
                            vec![Symbol::Terminals(b"()".to_vec())],
                        ),
                        (
                            BinaryFraction::from_bigrational(ONE_R.clone() - prob_term),
                            vec![
                                Symbol::Terminals(b"(".to_vec()),
                                Symbol::Nonterminal(0),
                                Symbol::Terminals(b")".to_vec()),
                            ],
                        ),
                    ]),
                ),
            ]
            .iter()
            .cloned()
            .collect(),
        }
    }

    /// A prefix-free version of dyck1
    pub fn wrapped_nonempty_dyck1(prob_zs: f32, prob_term: f32) -> SCFG {
        let prob_zs = from_float(prob_zs).unwrap();
        let prob_term = from_float(prob_term).unwrap();
        SCFG {
            rules: [
                (
                    0 as N,
                    vec![RuleEntry {
                        probability: One::one(),
                        cumul_lower: Zero::zero(),
                        rhs: vec![
                            Symbol::Terminals(b"(".to_vec()),
                            Symbol::Nonterminal(1),
                            Symbol::Terminals(b")".to_vec()),
                        ],
                    }],
                ),
                (
                    1 as N,
                    vec![
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(prob_zs.clone()),
                            cumul_lower: Zero::zero(),
                            rhs: vec![Symbol::Nonterminal(2), Symbol::Nonterminal(1)],
                        },
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                ONE_R.clone() - prob_zs.clone(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(prob_zs),
                            rhs: vec![Symbol::Nonterminal(2)],
                        },
                    ],
                ),
                (
                    2 as N,
                    vec![
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(prob_term.clone()),
                            cumul_lower: Zero::zero(),
                            rhs: vec![Symbol::Terminals(b"()".to_vec())],
                        },
                        RuleEntry {
                            probability: BinaryFraction::from_bigrational(
                                ONE_R.clone() - prob_term.clone(),
                            ),
                            cumul_lower: BinaryFraction::from_bigrational(prob_term),
                            rhs: vec![
                                Symbol::Terminals(b"(".to_vec()),
                                Symbol::Nonterminal(1),
                                Symbol::Terminals(b")".to_vec()),
                            ],
                        },
                    ],
                ),
            ]
            .iter()
            .cloned()
            .collect(),
        }
    }
}
